home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / OTHERCST / JPSRC_FO / JVIRTMEM.C < prev    next >
Text File  |  1991-10-13  |  18KB  |  549 lines

  1. /*
  2.  * jvirtmem.c
  3.  *
  4.  * Copyright (C) 1991, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file provides the system-dependent memory allocation routines
  9.  * for the case where we can rely on virtual memory to handle large arrays.
  10.  *
  11.  * This includes some MS-DOS code just for trial purposes; "big" arrays will
  12.  * have to be handled with temp files on MS-DOS, so a real implementation of
  13.  * a DOS memory manager will probably be a separate file.  (See additional
  14.  * comments about big arrays, below.)
  15.  * 
  16.  * NB: allocation routines never return NULL.
  17.  * They should exit to error_exit if unsuccessful.
  18.  */
  19.  
  20. #include "jinclude.h"
  21.  
  22. #ifdef __STDC__
  23. #include <stdlib.h>        /* to declare malloc(), free() */
  24. #else
  25. extern void * malloc PP((size_t size));
  26. extern void free PP((void *ptr));
  27. #endif
  28.  
  29.  
  30. /* Insert system-specific definitions of far_malloc, far_free here. */
  31.  
  32. #ifndef NEED_FAR_POINTERS    /* Generic for non-braindamaged CPUs */
  33.  
  34. #define far_malloc(x)    malloc(x)
  35. #define far_free(x)    free(x)
  36.  
  37. #else /* NEED_FAR_POINTERS */
  38.  
  39. #ifdef __TURBOC__
  40. /* These definitions work for Turbo C */
  41. #include <alloc.h>        /* need farmalloc(), farfree() */
  42. #define far_malloc(x)    farmalloc(x)
  43. #define far_free(x)    farfree(x)
  44. #else
  45. #ifdef MSDOS
  46. /* These definitions work for Microsoft C and compatible compilers */
  47. #include <malloc.h>        /* need _fmalloc(), _ffree() */
  48. #define far_malloc(x)    _fmalloc(x)
  49. #define far_free(x)    _ffree(x)
  50. #endif
  51. #endif
  52.  
  53. #endif /* NEED_FAR_POINTERS */
  54.  
  55.  
  56. /*
  57.  * Some important notes:
  58.  *   The array alloc/dealloc routines are not merely a convenience;
  59.  *   on 80x86 machines the bottom-level pointers in an array are FAR
  60.  *   and thus may not be allocatable by alloc_small.
  61.  *
  62.  *   Also, it's not a good idea to try to merge the sarray and barray
  63.  *   routines, even though they are textually almost the same, because
  64.  *   samples are usually stored as bytes while coefficients are shorts.
  65.  *   Thus, in machines where byte pointers have a different representation
  66.  *   from word pointers, the resulting machine code could not be the same.
  67.  */
  68.  
  69.  
  70. static external_methods_ptr methods; /* saved for access to error_exit */
  71.  
  72.  
  73. #ifdef MEM_STATS        /* optional extra stuff for statistics */
  74.  
  75. #define MALLOC_OVERHEAD  (SIZEOF(char *)) /* assumed overhead per request */
  76. #define MALLOC_FAR_OVERHEAD  (SIZEOF(char FAR *)) /* for "far" storage */
  77.  
  78. static long total_num_small = 0;    /* total # of small objects alloced */
  79. static long total_bytes_small = 0;    /* total bytes requested */
  80. static long cur_num_small = 0;        /* # currently alloced */
  81. static long max_num_small = 0;        /* max simultaneously alloced */
  82.  
  83. #ifdef NEED_FAR_POINTERS
  84. static long total_num_medium = 0;    /* total # of medium objects alloced */
  85. static long total_bytes_medium = 0;    /* total bytes requested */
  86. static long cur_num_medium = 0;        /* # currently alloced */
  87. static long max_num_medium = 0;        /* max simultaneously alloced */
  88. #endif
  89.  
  90. static long total_num_sarray = 0;    /* total # of sarray objects alloced */
  91. static long total_bytes_sarray = 0;    /* total bytes requested */
  92. static long cur_num_sarray = 0;        /* # currently alloced */
  93. static long max_num_sarray = 0;        /* max simultaneously alloced */
  94.  
  95. static long total_num_barray = 0;    /* total # of barray objects alloced */
  96. static long total_bytes_barray = 0;    /* total bytes requested */
  97. static long cur_num_barray = 0;        /* # currently alloced */
  98. static long max_num_barray = 0;        /* max simultaneously alloced */
  99.  
  100.  
  101. GLOBAL void
  102. j_mem_stats (void)
  103. {
  104.   /* since this is only a debugging stub, we can cheat a little on the
  105.    * trace message mechanism... helps 'cuz trace can't handle longs.
  106.    */
  107.   fprintf(stderr, "total_num_small = %ld\n", total_num_small);
  108.   fprintf(stderr, "total_bytes_small = %ld\n", total_bytes_small);
  109.   if (cur_num_small)
  110.     fprintf(stderr, "CUR_NUM_SMALL = %ld\n", cur_num_small);
  111.   fprintf(stderr, "max_num_small = %ld\n", max_num_small);
  112.   
  113. #ifdef NEED_FAR_POINTERS
  114.   fprintf(stderr, "total_num_medium = %ld\n", total_num_medium);
  115.   fprintf(stderr, "total_bytes_medium = %ld\n", total_bytes_medium);
  116.   if (cur_num_medium)
  117.     fprintf(stderr, "CUR_NUM_MEDIUM = %ld\n", cur_num_medium);
  118.   fprintf(stderr, "max_num_medium = %ld\n", max_num_medium);
  119. #endif
  120.   
  121.   fprintf(stderr, "total_num_sarray = %ld\n", total_num_sarray);
  122.   fprintf(stderr, "total_bytes_sarray = %ld\n", total_bytes_sarray);
  123.   if (cur_num_sarray)
  124.     fprintf(stderr, "CUR_NUM_SARRAY = %ld\n", cur_num_sarray);
  125.   fprintf(stderr, "max_num_sarray = %ld\n", max_num_sarray);
  126.   
  127.   fprintf(stderr, "total_num_barray = %ld\n", total_num_barray);
  128.   fprintf(stderr, "total_bytes_barray = %ld\n", total_bytes_barray);
  129.   if (cur_num_barray)
  130.     fprintf(stderr, "CUR_NUM_BARRAY = %ld\n", cur_num_barray);
  131.   fprintf(stderr, "max_num_barray = %ld\n", max_num_barray);
  132. }
  133.  
  134. #endif /* MEM_STATS */
  135.  
  136.  
  137. LOCAL void
  138. out_of_memory (int which)
  139. /* Report an out-of-memory error and stop execution */
  140. /* If we compiled MEM_STATS support, report alloc requests before dying */
  141. {
  142. #ifdef MEM_STATS
  143.   j_mem_stats();
  144. #endif
  145.   ERREXIT1(methods, "Insufficient memory (case %d)", which);
  146. }
  147.  
  148.  
  149.  
  150. METHODDEF void *
  151. alloc_small (size_t sizeofobject)
  152. /* Allocate a "small" (all-in-memory) object */
  153. {
  154.   void * result;
  155.  
  156. #ifdef MEM_STATS
  157.   total_num_small++;
  158.   total_bytes_small += sizeofobject + MALLOC_OVERHEAD;
  159.   cur_num_small++;
  160.   if (cur_num_small > max_num_small) max_num_small = cur_num_small;
  161. #endif
  162.  
  163.   result = malloc(sizeofobject);
  164.   if (result == NULL)
  165.     out_of_memory(1);
  166.   return result;
  167. }
  168.  
  169.  
  170. METHODDEF void
  171. free_small (void *ptr)
  172. /* Free a "small" (all-in-memory) object */
  173. {
  174.   free(ptr);
  175.  
  176. #ifdef MEM_STATS
  177.   cur_num_small--;
  178. #endif
  179. }
  180.  
  181.  
  182. #ifdef NEED_FAR_POINTERS
  183.  
  184. METHODDEF void FAR *
  185. alloc_medium (size_t sizeofobject)
  186. /* Allocate a "medium" (all in memory, but in far heap) object */
  187. {
  188.   void FAR * result;
  189.  
  190. #ifdef MEM_STATS
  191.   total_num_medium++;
  192.   total_bytes_medium += sizeofobject + MALLOC_FAR_OVERHEAD;
  193.   cur_num_medium++;
  194.   if (cur_num_medium > max_num_medium) max_num_medium = cur_num_medium;
  195. #endif
  196.  
  197.   result = far_malloc(sizeofobject);
  198.   if (result == NULL)
  199.     out_of_memory(2);
  200.   return result;
  201. }
  202.  
  203.  
  204. METHODDEF void
  205. free_medium (void FAR *ptr)
  206. /* Free a "medium" (all in memory, but in far heap) object */
  207. {
  208.   far_free(ptr);
  209.  
  210. #ifdef MEM_STATS
  211.   cur_num_medium--;
  212. #endif
  213. }
  214.  
  215. #endif /* NEED_FAR_POINTERS */
  216.  
  217.  
  218. METHODDEF JSAMPARRAY
  219. alloc_small_sarray (long samplesperrow, long numrows)
  220. /* Allocate a "small" (all-in-memory) 2-D sample array */
  221. {
  222.   JSAMPARRAY result;
  223.   long i;
  224.  
  225. #ifdef MEM_STATS
  226.   total_num_sarray++;
  227.   total_bytes_sarray += (samplesperrow * SIZEOF(JSAMPLE) + MALLOC_FAR_OVERHEAD)
  228.             * numrows;
  229.   cur_num_sarray++;
  230.   if (cur_num_sarray > max_num_sarray) max_num_sarray = cur_num_sarray;
  231. #endif
  232.  
  233.   /* Get space for row pointers; this is always "near" on 80x86 */
  234.   result = (JSAMPARRAY) alloc_small((size_t) (numrows * SIZEOF(JSAMPROW)));
  235.  
  236.   /* Get the rows themselves; on 80x86 these are "far" */
  237.   for (i = 0; i < numrows; i++) {
  238.     result[i] = (JSAMPROW) far_malloc((size_t) (samplesperrow * SIZEOF(JSAMPLE)));
  239.     if (result[i] == NULL)
  240.       out_of_memory(3);
  241.   }
  242.  
  243.   return result;
  244. }
  245.  
  246.  
  247. METHODDEF void
  248. free_small_sarray (JSAMPARRAY ptr, long numrows)
  249. /* Free a "small" (all-in-memory) 2-D sample array */
  250. {
  251.   long i;
  252.  
  253.   /* Free the rows themselves; on 80x86 these are "far" */
  254.   for (i = 0; i < numrows; i++) {
  255.     far_free((void FAR *) ptr[i]);
  256.   }
  257.  
  258.   /* Free space for row pointers; this is always "near" on 80x86 */
  259.   free_small((void *) ptr);
  260.  
  261. #ifdef MEM_STATS
  262.   cur_num_sarray--;
  263. #endif
  264. }
  265.  
  266.  
  267. METHODDEF JBLOCKARRAY
  268. alloc_small_barray (long blocksperrow, long numrows)
  269. /* Allocate a "small" (all-in-memory) 2-D coefficient-block array */
  270. {
  271.   JBLOCKARRAY result;
  272.   long i;
  273.  
  274. #ifdef MEM_STATS
  275.   total_num_barray++;
  276.   total_bytes_barray += (blocksperrow * SIZEOF(JBLOCK) + MALLOC_FAR_OVERHEAD)
  277.             * numrows;
  278.   cur_num_barray++;
  279.   if (cur_num_barray > max_num_barray) max_num_barray = cur_num_barray;
  280. #endif
  281.  
  282.   /* Get space for row pointers; this is always "near" on 80x86 */
  283.   result = (JBLOCKARRAY) alloc_small((size_t) (numrows * SIZEOF(JBLOCKROW)));
  284.  
  285.   /* Get the rows themselves; on 80x86 these are "far" */
  286.   for (i = 0; i < numrows; i++) {
  287.     result[i] = (JBLOCKROW) far_malloc((size_t) (blocksperrow * SIZEOF(JBLOCK)));
  288.     if (result[i] == NULL)
  289.       out_of_memory(4);
  290.   }
  291.  
  292.   return result;
  293. }
  294.  
  295.  
  296. METHODDEF void
  297. free_small_barray (JBLOCKARRAY ptr, long numrows)
  298. /* Free a "small" (all-in-memory) 2-D coefficient-block array */
  299. {
  300.   long i;
  301.  
  302.   /* Free the rows themselves; on 80x86 these are "far" */
  303.   for (i = 0; i < numrows; i++) {
  304.     far_free((void FAR *) ptr[i]);
  305.   }
  306.  
  307.   /* Free space for row pointers; this is always "near" on 80x86 */
  308.   free_small((void *) ptr);
  309.  
  310. #ifdef MEM_STATS
  311.   cur_num_barray--;
  312. #endif
  313. }
  314.  
  315.  
  316.  
  317. /*
  318.  * About "big" array management:
  319.  *
  320.  * To allow machines with limited memory to handle large images,
  321.  * all processing in the JPEG system is done a few pixel or block rows
  322.  * at a time.  The above "small" array routines are only used to allocate
  323.  * strip buffers (as wide as the image, but just a few rows high).
  324.  * In some cases multiple passes must be made over the data.  In these
  325.  * cases the "big" array routines are used.  The array is still accessed
  326.  * a strip at a time, but the memory manager must save the whole array
  327.  * for repeated accesses.  The intended implementation is that there is
  328.  * a strip buffer in memory (as high as is possible given the desired memory
  329.  * limit), plus a backing file that holds the rest of the array.
  330.  *
  331.  * The request_big_array routines are told the total size of the image (in case
  332.  * it is useful to know the total file size that will be needed).  They are
  333.  * also given the unit height, which is the number of rows that will be
  334.  * accessed at once; the in-memory buffer should usually be made a multiple of
  335.  * this height for best efficiency.
  336.  *
  337.  * The request routines create control blocks (and may open backing files),
  338.  * but they don't create the in-memory buffers.  This is postponed until
  339.  * alloc_big_arrays is called.  At that time the total amount of space needed
  340.  * is known (approximately, anyway), so free memory can be divided up fairly.
  341.  *
  342.  * The access_big_array routines are responsible for making a specific strip
  343.  * area accessible (after reading or writing the backing file, if necessary).
  344.  * Note that the access routines are told whether the caller intends to modify
  345.  * the accessed strip; during a read-only pass this saves having to rewrite
  346.  * data to disk.
  347.  *
  348.  * The typical access pattern is one top-to-bottom pass to write the data,
  349.  * followed by one or more read-only top-to-bottom passes.  However, other
  350.  * access patterns may occur while reading.  For example, translation of image
  351.  * formats that use bottom-to-top scan order will require bottom-to-top read
  352.  * passes.  The memory manager need not support multiple write passes nor
  353.  * funny write orders (meaning that rearranging rows must be handled while
  354.  * reading data out of the big array, not while putting it in).
  355.  *
  356.  * In current usage, the access requests are always for nonoverlapping strips;
  357.  * that is, successive access start_row numbers always differ by exactly the
  358.  * unitheight.  This allows fairly simple buffer dump/reload logic if the
  359.  * in-memory buffer is made a multiple of the unitheight.  It would be
  360.  * possible to keep subsampled rather than fullsize data in the "big" arrays,
  361.  * thus reducing temp file size, if we supported overlapping strip access
  362.  * (access requests differing by less than the unitheight).  At the moment
  363.  * I don't believe this is worth the extra complexity.
  364.  *
  365.  * This particular implementation doesn't use temp files; the whole of a big
  366.  * array is allocated in (virtual) memory, and any swapping is done behind the
  367.  * scenes by the operating system.
  368.  */
  369.  
  370.  
  371.  
  372. /* The control blocks for virtual arrays.
  373.  * These are pretty minimal in this implementation.
  374.  * Note: in this implementation we could realize big arrays
  375.  * at request time and make alloc_big_arrays a no-op;
  376.  * however, doing it separately keeps callers honest.
  377.  */
  378.  
  379. struct big_sarray_control {
  380.     JSAMPARRAY mem_buffer;    /* memory buffer (the whole thing, here) */
  381.     long rows_in_mem;    /* Height of memory buffer */
  382.     long samplesperrow;    /* Width of memory buffer */
  383.     long unitheight;    /* # of rows accessed by access_big_sarray() */
  384.     big_sarray_ptr next;    /* list link for unrealized arrays */
  385. };
  386.  
  387. struct big_barray_control {
  388.     JBLOCKARRAY mem_buffer;    /* memory buffer (the whole thing, here) */
  389.     long rows_in_mem;    /* Height of memory buffer */
  390.     long blocksperrow;    /* Width of memory buffer */
  391.     long unitheight;    /* # of rows accessed by access_big_barray() */
  392.     big_barray_ptr next;    /* list link for unrealized arrays */
  393. };
  394.  
  395.  
  396. /* Headers of lists of control blocks for unrealized big arrays */
  397. static big_sarray_ptr unalloced_sarrays;
  398. static big_barray_ptr unalloced_barrays;
  399.  
  400.  
  401. METHODDEF big_sarray_ptr
  402. request_big_sarray (long samplesperrow, long numrows, long unitheight)
  403. /* Request a "big" (virtual-memory) 2-D sample array */
  404. {
  405.   big_sarray_ptr result;
  406.  
  407.   /* get control block */
  408.   result = (big_sarray_ptr) alloc_small(SIZEOF(struct big_sarray_control));
  409.  
  410.   result->mem_buffer = NULL;    /* lets access routine spot premature access */
  411.   result->rows_in_mem = numrows;
  412.   result->samplesperrow = samplesperrow;
  413.   result->unitheight = unitheight;
  414.   result->next = unalloced_sarrays; /* add to list of unallocated arrays */
  415.   unalloced_sarrays = result;
  416.  
  417.   return result;
  418. }
  419.  
  420.  
  421. METHODDEF big_barray_ptr
  422. request_big_barray (long blocksperrow, long numrows, long unitheight)
  423. /* Request a "big" (virtual-memory) 2-D coefficient-block array */
  424. {
  425.   big_barray_ptr result;
  426.  
  427.   /* get control block */
  428.   result = (big_barray_ptr) alloc_small(SIZEOF(struct big_barray_control));
  429.  
  430.   result->mem_buffer = NULL;    /* lets access routine spot premature access */
  431.   result->rows_in_mem = numrows;
  432.   result->blocksperrow = blocksperrow;
  433.   result->unitheight = unitheight;
  434.   result->next = unalloced_barrays; /* add to list of unallocated arrays */
  435.   unalloced_barrays = result;
  436.  
  437.   return result;
  438. }
  439.  
  440.  
  441. METHODDEF void
  442. alloc_big_arrays (long extra_small_samples, long extra_small_blocks,
  443.           long extra_medium_space)
  444. /* Allocate the in-memory buffers for any unrealized "big" arrays */
  445. /* 'extra' values are upper bounds for total future small-array requests */
  446. /* and far-heap requests */
  447. {
  448.   /* In this implementation we just malloc the whole arrays */
  449.   /* and expect the system's virtual memory to worry about swapping them */
  450.   big_sarray_ptr sptr;
  451.   big_barray_ptr bptr;
  452.  
  453.   for (sptr = unalloced_sarrays; sptr != NULL; sptr = sptr->next) {
  454.     sptr->mem_buffer = alloc_small_sarray(sptr->samplesperrow,
  455.                       sptr->rows_in_mem);
  456.   }
  457.  
  458.   for (bptr = unalloced_barrays; bptr != NULL; bptr = bptr->next) {
  459.     bptr->mem_buffer = alloc_small_barray(bptr->blocksperrow,
  460.                       bptr->rows_in_mem);
  461.   }
  462.  
  463.   unalloced_sarrays = NULL;    /* reset for possible future cycles */
  464.   unalloced_barrays = NULL;
  465. }
  466.  
  467.  
  468. METHODDEF JSAMPARRAY
  469. access_big_sarray (big_sarray_ptr ptr, long start_row, boolean writable)
  470. /* Access the part of a "big" sample array starting at start_row */
  471. /* and extending for ptr->unitheight rows.  writable is true if  */
  472. /* caller intends to modify the accessed area. */
  473. {
  474.   /* debugging check */
  475.   if (start_row < 0 || start_row+ptr->unitheight > ptr->rows_in_mem ||
  476.       ptr->mem_buffer == NULL)
  477.     ERREXIT(methods, "Bogus access_big_sarray request");
  478.  
  479.   return ptr->mem_buffer + start_row;
  480. }
  481.  
  482.  
  483. METHODDEF JBLOCKARRAY
  484. access_big_barray (big_barray_ptr ptr, long start_row, boolean writable)
  485. /* Access the part of a "big" coefficient-block array starting at start_row */
  486. /* and extending for ptr->unitheight rows.  writable is true if  */
  487. /* caller intends to modify the accessed area. */
  488. {
  489.   /* debugging check */
  490.   if (start_row < 0 || start_row+ptr->unitheight > ptr->rows_in_mem ||
  491.       ptr->mem_buffer == NULL)
  492.     ERREXIT(methods, "Bogus access_big_barray request");
  493.  
  494.   return ptr->mem_buffer + start_row;
  495. }
  496.  
  497.  
  498. METHODDEF void
  499. free_big_sarray (big_sarray_ptr ptr)
  500. /* Free a "big" (virtual-memory) 2-D sample array */
  501. {
  502.   free_small_sarray(ptr->mem_buffer, ptr->rows_in_mem);
  503.   free_small((void *) ptr);    /* free the control block too */
  504. }
  505.  
  506.  
  507. METHODDEF void
  508. free_big_barray (big_barray_ptr ptr)
  509. /* Free a "big" (virtual-memory) 2-D coefficient-block array */
  510. {
  511.   free_small_barray(ptr->mem_buffer, ptr->rows_in_mem);
  512.   free_small((void *) ptr);    /* free the control block too */
  513. }
  514.  
  515.  
  516.  
  517. /*
  518.  * The method selection routine for virtual memory systems.
  519.  * The system-dependent setup routine should call this routine
  520.  * to install the necessary method pointers in the supplied struct.
  521.  */
  522.  
  523. GLOBAL void
  524. jselvirtmem (external_methods_ptr emethods)
  525. {
  526.   methods = emethods;        /* save struct addr for error exit access */
  527.  
  528.   emethods->alloc_small = alloc_small;
  529.   emethods->free_small = free_small;
  530. #ifdef NEED_FAR_POINTERS
  531.   emethods->alloc_medium = alloc_medium;
  532.   emethods->free_medium = free_medium;
  533. #endif
  534.   emethods->alloc_small_sarray = alloc_small_sarray;
  535.   emethods->free_small_sarray = free_small_sarray;
  536.   emethods->alloc_small_barray = alloc_small_barray;
  537.   emethods->free_small_barray = free_small_barray;
  538.   emethods->request_big_sarray = request_big_sarray;
  539.   emethods->request_big_barray = request_big_barray;
  540.   emethods->alloc_big_arrays = alloc_big_arrays;
  541.   emethods->access_big_sarray = access_big_sarray;
  542.   emethods->access_big_barray = access_big_barray;
  543.   emethods->free_big_sarray = free_big_sarray;
  544.   emethods->free_big_barray = free_big_barray;
  545.  
  546.   unalloced_sarrays = NULL;    /* make sure list headers are empty */
  547.   unalloced_barrays = NULL;
  548. }
  549.